/**
 * 
 */
package neptune.manager.utils;

import java.util.BitSet;

/**
 * @author Roberto Bifulco [RobertoBifulco.it] [info@robertoBifulco.it]
 * 
 */
public class BitUtils {

	/**
	 * Converte un {@link UnsignedByte} in un BitSet. L'ordine e' dal bit meno
	 * significativo a quello piu' significativo (0 bit meno significativo, 7
	 * bit piu' significativo).
	 * 
	 * @param byteVal
	 * @return
	 */
	public static BitSet getBitValue(UnsignedByte byteVal) {
		BitSet bit = new BitSet(8);
		int val = byteVal.getValue();
		for (int i = 7; i >= 0; i--) {
			int toSub = (int) (Math.pow(2, i));
			if (val - toSub >= 0) {
				bit.set(i);
				val -= toSub;
			}
		}
		return bit;
	}

	/**
	 * Converte un array di {@link UnsignedByte} in un BitSet. L'ordine e' dal
	 * bit meno significativo a quello piu' significativo (0 bit meno
	 * significativo, 7 bit piu' significativo). Gli UnsignedByte sono
	 * riorganizzati secondo questo ordine. Quindi, l'UnsignedByte di indice 0
	 * avra' i suoi 8 bit alla fine del BitSet
	 * 
	 * @param byteVal
	 * @return
	 */
	public static BitSet getBitValue(UnsignedByte[] byteVal) {
		BitSet bit = new BitSet(8 * byteVal.length);
		for (int i = 0; i < byteVal.length; i++) {
			for (int k = 0; k < getBitValue(byteVal[i]).length(); k++) {
				bit.set((3 - i) * 8 + k, getBitValue(byteVal[i]).get(k));
			}
		}
		return bit;
	}

	/**
	 * Converte un BitSet di 8 bit in un {@link UnsignedByte}
	 * 
	 * @param bitVal
	 * @return
	 * @throws IllegalValueException
	 */
	public static UnsignedByte getByteValue(BitSet bitVal)
			throws IllegalValueException {
		int val = 0;
		for (int i = 0; i < bitVal.size(); i++) {
			if (bitVal.get(i))
				val += Math.pow(2, i);
		}

		return new UnsignedByte(val);
	}

	/**
	 * Incrementa un BitSet del valore 1. Il BitSet ha i bit organizzati dal
	 * meno significativo (indice 0) al piu' significativo. Se l'incremento
	 * genera overflow, il metodo restituisce true. La valutazione dell'overflow
	 * e' fatta in base alla lunghezza della stringa di bit contenuta nel
	 * bitSet, che viene specificata con il parametro numberOfBits.<br>
	 * <br>
	 * Il parametro limit indica su quali cifre, a partire dalla piu'
	 * significativa, si deve effettuare l'incremento.<br>
	 * <br>
	 * Esempi:<br>
	 * Stringa: 00101 numberOfBits: 5 limit: 3<br>
	 * Risultato: 00011<br>
	 * <br>
	 * Stringa: 00101 numberOfBits: 5 limit: 5<br>
	 * Risultato: 10101<br>
	 * <br>
	 * 
	 * @param bitSet
	 * @param limit
	 * @return
	 */
	public static boolean incrementBits(BitSet bitSet, int limit,
			int numberOfBits) {
		int i = numberOfBits - limit;

		while (bitSet.get(i) && i < numberOfBits) {
			bitSet.set(i, false);
			i++;
		}
		if (i < numberOfBits)
			bitSet.set(i);
		else
			return true;
		return false;
	}
}
